/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hxg.portmgr.core.find;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import util.pinyinUtils;

/**
 *
 * @author hxg
 */
public class Find {

    private static final Logger logger = Logger.getLogger(Find.class.getName());

    public Find(Object obj, Object target, MatchLevel level) {
        this.resultObject = obj;
        this.target = target;
        this.level = level;
    }

    /**
     * 
     * @param obj 被查找到的对象
     * @param target 搜索的目标值,可能是String,目前也仅支持String,以后可能支持List等,具体看情况
     * @param level
     * @param find 
     */
    public Find(Object obj, Object target, MatchLevel level, Find find) {
        this.resultObject = obj;
        this.target = target;
        this.level = level;
        this.fatherFind = find;
    }
    Object resultObject;
    Object target;
    MatchLevel level;
    Find fatherFind = null;

    public MatchLevel getLevel() {
        return level;
    }

    public Object getResultObject() {
        return resultObject;
    }

    public Object getTarget() {
        return target;
    }

    public Find getFatherFind() {
        return fatherFind;
    }

    public void setFatherFind(Find fatherFind) {
        this.fatherFind = fatherFind;
    }

    @Override
    public String toString() {
        if (fatherFind != null) {
            return fatherFind.toString() + " " + resultObject.toString() + "[" + target.toString() + "]";
        } else {
            return resultObject.toString() + "[" + target.toString() + "]";
        }
    }
    
    /**
     * 
     * @param srcObjects 源被搜索对象
     * @param c 源被搜索对象的类
     * @param attr 被搜索的属性
     * @param key 被搜索的关键值
     * @param fatherfind 父搜索结果,其实对搜索过程无意义,但是可以用来构成搜索链
     * @return 返回搜索结果
     */

    public static List<Find> find(Object[] srcObjects, Class c, String attr, String key, Find fatherfind) {
        List<Find> list = new ArrayList();

        //首先,获得attr对应的Field或Method,并做一个标记
        Field field = null;
        Index index = null;
        Method method = null;
        //Field[] fields = srcClass.getDeclaredFields();
        for (Field f : c.getDeclaredFields()) {
            Index idx = f.getAnnotation(Index.class);
            if (idx != null) {
                if (idx.name().toLowerCase().equals(attr.toLowerCase())) {
                    field = f;
                    field.setAccessible(true);
                    index = idx;
                }
            }
        }
        if (field == null) {
            for (Method m : c.getDeclaredMethods()) {
                Index idx = m.getAnnotation(Index.class);
                if (idx != null) {
                    if (idx.name().toLowerCase().equals(attr.toLowerCase())) {
                        method = m;
                        index = idx;
                    }
                }
            }
        }
        //假如类中有Index标注的字段或方法,就开始搜索
        if (index != null) {
            for (Object object : srcObjects) {
                //注意,仅扫描指定的类
                if (c.isInstance(object)) {
                    try {
                        Object value;
                        if (field != null) {
                            value = field.get(object);
                        } else {
                            //在index不为NUll时,如果Filed为NULL,则METHOD一定不为NULL
                            try {
                                value = method.invoke(object);
                            } catch (InvocationTargetException ex) {
                                value = null;
                                Logger.getLogger(Find.class.getName()).log(Level.INFO, null, ex);
                            }
                        }
                        if (value != null) {
                            MatchLevel level = Matches(value, index, key); //注意返回的LEVEL一定是大于Index的
                            if (level != MatchLevel.NotMatch) {
                                list.add(new Find(object, value, level, fatherfind));
                            }
                        }
                    } catch (Exception ex) {
                        logger.log(Level.SEVERE, null, ex);
                    }
                } else {
                    logger.log(Level.SEVERE, null, c.isInstance(object));
                    logger.log(Level.SEVERE, null, object.getClass().getSimpleName());
                }
            }
        }
        return list;
    }

    public static List<Find> find(Collection srcObjects, Class c, String attr, String key, Find fatherFind) {
        Object[] objs = srcObjects.toArray();
        return find(objs, c, attr, key, fatherFind);
    }

    private static MatchLevel Matches(Object obj, Index index, String key) {
        if (obj instanceof String) {
            String target = (String) obj;
            switch (index.level()) {
                case FullMatch:
                    if (target.equals(key)) {    //完全匹配
                        return MatchLevel.FullMatch;
                    } else {
                        return MatchLevel.NotMatch;
                    }
                case ContainMatch:
                    if (target.equals(key)) {    //完全匹配
                        return MatchLevel.FullMatch;
                    } else if (target.contains(key)) {
                        return MatchLevel.ContainMatch;
                    } else {
                        return MatchLevel.NotMatch;
                    }
                case BlurMatch:
                    if (target.equals(key)) {    //完全匹配
                        return MatchLevel.FullMatch;
                    } else if (target.contains(key)) {
                        return MatchLevel.ContainMatch;
                    } else if (blurMatches(key.toCharArray(), target.toCharArray())) {
                        return MatchLevel.BlurMatch;
                    }
                    return MatchLevel.NotMatch;
                case PinYinBlurMatch:
                    if (target.equals(key)) {    //完全匹配
                        return MatchLevel.FullMatch;
                    } else if (target.contains(key)) {
                        return MatchLevel.ContainMatch;
                    } else if (blurMatches(key.toCharArray(), target.toCharArray())) {
                        return MatchLevel.BlurMatch;
                    } else if (blurMatches(key.toCharArray(), (pinyinUtils.getPinyinOfString(target) + target).toCharArray())) {
                        return MatchLevel.PinYinBlurMatch;
                    }
                    return MatchLevel.NotMatch;
                default:
                    return MatchLevel.NotMatch;
            }
        }
        return MatchLevel.NotMatch;
    }

    private static boolean blurMatches(char[] keys, char[] targets) {
        int i = 0;
        for (char ch : targets) {
            if (ch == keys[i]) {
                i++;
                if (i >= keys.length) {
                    return true;
                }
            }
        }
        return false;
    }
}
